home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c++ / 595 < prev    next >
Encoding:
Text File  |  1996-08-06  |  7.0 KB  |  165 lines

  1. Path: chronicle.mti.sgi.com!austern
  2. From: kuehl@uzwil.informatik.uni-konstanz.de (Dietmar Kuehl)
  3. Newsgroups: comp.std.c++
  4. Subject: Re: operators new[]/delete[]
  5. Date: 29 Feb 1996 09:14:42 PST
  6. Organization: FakultΣt fⁿr Mathematik und Informatik
  7. Approved: austern@isolde.mti.sgi.com
  8. Message-ID: <4h4agc$b1m@news.BelWue.DE>
  9. References: <313166CF.11C2@orbotech.co.il> <4gu414$62u@mulga.cs.mu.OZ.AU> <4h24c2$pq@caesar.ultra.net>
  10. Reply-To: dietmar.kuehl@uni-konstanz.de
  11. NNTP-Posting-Host: isolde.mti.sgi.com
  12. X-Original-Date: 29 Feb 1996 13:42:36 GMT
  13. X-Newsreader: TIN [version 1.2 PL2]
  14. X-Auth: PGPMoose V1.1 PGP comp.std.c++
  15.     iQBVAwUBMTXfEEy4NqrwXLNJAQHRHAH/as7SoRd/95XaCs0i8eQNAYtXQd/KMr6p
  16.     1iSNVwpAkkJpP92slwmxiHc/KUh6qcyXI+C5ZiYvbS/3tulgEKEXig==
  17.     =vxQ2
  18. Originator: austern@isolde.mti.sgi.com
  19.  
  20. Hi,
  21.  
  22. Pablo Halpern (phalpern@truffle.ultranet.com) wrote:
  23. :   template <class T>
  24. :   T* dup_array(const T* p, size_t s)
  25. :   {
  26. :     T *p2 = reinterpret_cast<T*> new char[s * sizeof(T)];  // note 1
  27.  
  28. This is in no ways portable. However, it IS portable to allocate "raw"
  29. memory with 'operator new()' or 'operator new[]()'. See below...
  30. :   }
  31.  
  32. :   void f(T* p, size_t s)
  33. :   {
  34. :     T* newp = dup_array(p, s);
  35. :     // do something with newp
  36. :     delete [] newp;     // note 2
  37.  
  38. This results indeed in undefined behavior.
  39. :   }
  40.  
  41. : I believe that something similar to the line marked "note 1" is common
  42. : practice for this sort of operation. However, I believe that the line
  43. : marked "note 2" is undefined behavior. Is there a way in the standard
  44. : can be modified so that the above code becomes well-defined and works as
  45. : intended? How does the STL deal with this in its "unitialized copy"
  46. : operation?
  47.  
  48. There is no need to modify the standard because there is already a
  49. method available to deal with "raw" memory (see below), which e.g. use
  50. by STL.
  51.  
  52. : There is another way to allocate raw memory, but here the operations are
  53. : even less defined (I believe):
  54.  
  55. The operations are well defined, if used correctly...
  56.  
  57. :    void *p2 = operator new[] (s * sizeof(T));
  58. :    delete p2;  // What does this do? p2 was not the result of a normal
  59. :                // new expression.
  60. :    delete reinterpret_cast<T*> p2;  // What does this do?
  61.  
  62. Both attempts to release the memory pointed to by 'p2' result in
  63. undefined behavior: 'delete' can only be applied to objects allocated
  64. with 'new T' (for some type 'T').  Likewise, 'delete[]' can only release
  65. array objects allocated with 'new T[i]' (for some type 'T' and some
  66. value 'i'). The whole trick is to distinguish 'new T' from 'operator
  67. new()' and 'delete ptr' from 'operator delete()' (and correspondingly
  68. the array variants):  They are just different operations (see e.g.
  69. "More Effective C++", S.Meyers, Addison-Wesly, Item 8).
  70.  
  71. I will describe the stuff for arrays because apparently the "renew"
  72. topic is currently "in" :-) 'new T[i]' does something like:
  73.  
  74.   #include <new>
  75.  
  76.   T *new_T_array(size_t size) // a "homegrown" 'new T[size]'
  77.   {
  78.     // Allocate enough memory to hold the requested array plus
  79.     // additional information about the size of the array. This
  80.     // is as written NOT portable (insufficient alignment) but it
  81.     // is also not necessary to do the non-portable stuff, if the
  82.     // operations are encapsulated in an array class like 'vector':
  83.     // the size can be stored somewhere else.
  84.  
  85.     void   *ptr  = operator new[](sizeof(T) + sizeof(size_t));
  86.     size_t *sptr = static_cast<size_t*>(ptr);
  87.     *sptr = size; // first store the size
  88.     // .. then get the address of the actual array
  89.     T *Tptr = static_cast<T*>(static_cast<void*>(sptr + 1));
  90.  
  91.     // now initialize the array
  92.     for (size_t idx = 0; i < size; ++i)
  93.       operator new(Tptr + idx) T(); 
  94.     return Tptr;
  95.   }
  96.  
  97. However, this is NOT how it is indeed implemented but it depicts what
  98. is basically going on and how it COULD be implemented (well, not
  99. really: It is also necessary to take care of exceptions in the
  100. constructors and to release constructed objects if there is an
  101. exception). In particular, it shows the basics how to implement an own
  102. routine to allocate an array which basically feels like a built-in
  103. array (i.e. how 'operator new[]()' and "placement new" are used to
  104. create and initialize the array). Unfortunately, you cannot 'delete[]'
  105. an array created with 'new_T_array()'. Instead, you have to mimic the
  106. behavior of 'delete[]' using explicit destruction and 'operator
  107. delete[]()'.  Here are the details:
  108.  
  109.   void delete_T_array(T *Tptr)
  110.   {
  111.     // Again this code is somewhat non-portable but againn this doesn't
  112.     // matter because an array class can do a better (and portable) job
  113.     // by storing the size somewhere else.
  114.  
  115.     // First retrieve the size from where it was store in 'new_T_array()':
  116.     size_t *sptr = static_cast<size_t*>(static_cast<void*>(Tptr)) - 1;
  117.     // ... then release the individual objects in the reverse order
  118.     // constructed:
  119.     for (size_t idx = *sptr; idx-- > 0; )
  120.       Tptr[idx].~T();
  121.     
  122.     // Finally release the allocated "raw" memory
  123.     operator delete[](static_cast<void*>(sptr));
  124.   }
  125.  
  126. Again, this is basically how it works (but e.g. with exception handling
  127. excluded). If you need to do similar stuff, you can do es like this.
  128. However, you should place such stuff in a class (e.g. because it is
  129. much simpler to do this portable). If do so, you are likely to end up
  130. with a class similar to 'vector'.  So, why bother...?
  131.  
  132. Concerning the 'renew' problematic: Using a combination of the stuff in
  133. 'new_T_array()' and 'delete_T_array()' you can implement a
  134. 'renew_T_array()' which is capable to 'renew' arrays allocated with
  135. 'new_T_array()' (or, even easier, if used with in a class to 'renew'
  136. the internal storage used to represent the array).  However, there is
  137. still a minor inefficiency in comparison with 'realloc()': The need to
  138. store the size. Since the memory management almost certainly "knows"
  139. the size of the memory object somehow (I guess in all implementation it
  140. does know the size but I can also imagine that there could be a strange
  141. environment where this is not the case...), the number of elements in
  142. the memory object could potentially be deduced from this size. There is
  143. no portable method to do so. But I believe that this additional
  144. 'size_t' is not that heavy-weight to be a real problem which justifies
  145. some very specific language extension.
  146.  
  147. : How do we solve these problems in a standard-conforming way. Does there
  148. : need to be special language for char arrays or void * allocations. (Or
  149. : is there already? I haven't found it.)
  150.  
  151. How to solve this problems in a standard-conforming way: See above.
  152. ...  and no, neither are there special allocations for 'char' arrays or
  153. 'void*', nor are they needed.
  154. --
  155. dietmar.kuehl@uni-konstanz.de
  156. http://www.informatik.uni-konstanz.de/~kuehl
  157. I am a realistic optimist - that's why I appear to be slightly pessimistic
  158. ---
  159. [ comp.std.c++ is moderated.  To submit articles: Try just posting with your 
  160.                 newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  161.   comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  162.   Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  163.   Comments? mailto:std-c++-request@ncar.ucar.edu 
  164. ]
  165.